//
// Created by guoshunw on 23-12-17.
//

#ifndef CMAKE_HELLO_MACRO_H
#define CMAKE_HELLO_MACRO_H

#include <iostream>
#include <memory>
#include <mutex>
#include <type_traits>
#include <utility>


#define UNUSED(param) (void) param

#define DEFINE_TYPE_TRAIT(name, func)                          \
    template<typename T>                                       \
    struct name {                                              \
        template<typename Class>                               \
        static constexpr bool Test(decltype(&Class::func) *) { \
            return true;                                       \
        }                                                      \
        template<typename>                                     \
        static constexpr bool Test(...) {                      \
            return false;                                      \
        }                                                      \
                                                               \
        static constexpr bool value = Test<T>(nullptr);        \
    };                                                         \
                                                               \
    template<typename T>                                       \
    constexpr bool name<T>::value;

DEFINE_TYPE_TRAIT(HasShutdown, Shutdown)

template<typename T>
typename std::enable_if<HasShutdown<T>::value>::type CallShutdown(T *instance) {
    instance->Shutdown();
}

template<typename T>
typename std::enable_if<!HasShutdown<T>::value>::type CallShutdown(
        T *instance) {
    (void) instance;
}

#define DISALLOW_COPY_AND_ASSIGN(classname) \
    classname(const classname &) = delete;  \
    classname &operator=(const classname &) = delete;

#define DECLARE_SINGLETON(classname)                                                                        \
public:                                                                                                     \
    static auto Instance(bool create_if_needed = true) {                                                    \
        static std::shared_ptr<classname> instance{};                                                       \
        if (!instance && create_if_needed) {                                                                \
            static std::once_flag flag;                                                                     \
            std::call_once(flag,                                                                            \
                           [&] { instance = std::shared_ptr<classname>(new (std::nothrow) classname()); }); \
        }                                                                                                   \
        return instance;                                                                                    \
    }                                                                                                       \
                                                                                                            \
    static void CleanUp() {                                                                                 \
        auto instance = Instance(false);                                                                    \
        if (instance) {                                                                                     \
            CallShutdown(instance.get());                                                                   \
        }                                                                                                   \
    }                                                                                                       \
                                                                                                            \
private:                                                                                                    \
    classname() = default;                                                                                  \
    DISALLOW_COPY_AND_ASSIGN(classname)

#endif//CMAKE_HELLO_MACRO_H
